package com.ruoyi.business.service;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.business.*;
import com.ruoyi.business.ao.RefundAO;
import com.ruoyi.business.ao.UserAO;
import com.ruoyi.business.ao.UserRegisterAO;
import com.ruoyi.business.bo.*;
import com.ruoyi.business.enums.*;
import com.ruoyi.business.mapper.*;
import com.ruoyi.business.qo.UserQO;
import com.ruoyi.business.vo.AccountDetailVO;
import com.ruoyi.business.vo.UserListVO;
import com.ruoyi.business.vo.UserVO;
import com.ruoyi.common.common.CommonEnum;
import com.ruoyi.common.common.GlobalValue;
import com.ruoyi.common.common.ResultBody;
import com.ruoyi.common.exception.BizException;
import com.ruoyi.common.utils.DateUtil;
import com.ruoyi.common.utils.IdUtils;
import com.ruoyi.common.utils.JwtUtil;
import com.ruoyi.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;


/**
 * @title: UserService
 * @copyright: copyright (c) 2021
 * @author: jiangguanjun
 * @date: 2023/2/8 12:55
 * @firstReview:
 * @lastReview:
 * @desc: 用户相关
 */
@Slf4j
@Component
public class UserService  {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserBuyVipMapper userBuyVipMapper ;

    @Autowired
    private RedisTemplate redisTemplate ;

    @Autowired
    private PushMessageService pushMessageService ;
    @Autowired
    private WechartService wechartService ;

    @Autowired
    private PayService payService ;

    @Autowired
    private OrderMapper orderMapper ;

    @Autowired
    private AccountDetailMapper accountDetailMapper ;

    @Autowired
    private RefundMapper refundMapper ;

    @Value("${weixin.template.buyVip.templateId}")
    private String templateId  ;
    @Value("${weixin.template.buyVip.title}")
    private String title  ;

    @Value("${weixin.template.buyVip.remark}")
    private String remark  ;

    @Value("${weixin.app_id}")
    private String appId ;

    @Value("${weixin.secret}")
    private String secret ;

    @Value("${tencent.sms.codeTemplateId}")
    private String codeTemplateId ;
    // buy_vip_notify
    @Value("${weixinpay.buy_vip_notify}")
    private String buyVipNotify ;

    @Value("${vip.price}")
    private Integer vipPrice  ;

    @Value("${weixinpay.notify_base_url}")
    private String notifyBase  ;
    @Value("${weixinpay.buy_vip_refund_notify}")
    private String buyVipRefundNotify ;

    public ResultBody edit(UserAO userAO) {
        User user = new User() ;
        BeanUtils.copyProperties(userAO,user);
        int res = userMapper.updateByPrimaryKeySelective(user) ;
        if(res>0){
            return ResultBody.success() ;
        }
        return ResultBody.error(CommonEnum.USER_UPDATE_ERROR) ;
    }

    public ResultBody queryByPage(UserQO userQO) {
        MyPage myPage = PageConfig.getPage() ;
        Page<UserListVO> page = new Page<>(myPage.getPageNum(),myPage.getPageSize()) ;
        IPage<UserListVO> iPage = userMapper.queryPage(page,userQO) ;
        List<UserListVO> userListVOList = iPage.getRecords() ;
        if(CollectionUtils.isEmpty(userListVOList)){
            return ResultBody.success(iPage) ;
        }
        // 丰富信息
        userListVOList.forEach(userListVO -> {
            userListVO.setBuyoutStr(BuyoutEnum.getDescByCode(userListVO.getBuyout()));
            userListVO.setStatusStr(StatusEnum.getDescByCode(userListVO.getStatus()));
            userListVO.setVipStr(VipEnum.getDescByCode(userListVO.getVip()));
        });
        iPage = iPage.setRecords(userListVOList) ;

        return ResultBody.success(iPage) ;
    }

    public User getById(Long id) {
        return userMapper.selectByPrimaryKey(id) ;
    }

    @Transactional
    public ResultBody buyVip(Integer vipPrice, Long userId) {
        String orderNo = GlobalValue.BUY_VIP_ORDER_FREFIX+ IdUtils.getId() ;
        User userDB = userMapper.selectByPrimaryKey(userId) ;
        // TODO 支付会员金额
        PayBO payBO = new PayBO() ;
        payBO.setDescription("购买会员");
        payBO.setOpenid(userDB.getOpenId());
        payBO.setNotifyUrl(buyVipNotify) ;
        payBO.setOutTradeNo(orderNo);
        payBO.setTotal(vipPrice);
        PayResultBO payResultBO = payService.pay(payBO) ;
        if(payResultBO == null){
            return ResultBody.error(CommonEnum.USER_BUY_VIP_ERROR) ;
        }


        Map<String , Date> timeMap = getStartTimeAndEndTime(userDB.getVipStartTime(),userDB.getVipEndTime()) ;
        Date startTime = timeMap.get("startTime") ;
        Date endTime = timeMap.get("endTime") ;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") ;
        log.info("结束时间：：：{}",simpleDateFormat.format(endTime));

        // 新增用户VIP购买记录表t_user_buy_vip
        UserBuyVip userBuyVip = new UserBuyVip() ;
        userBuyVip.setBuyEndTime(endTime);
        userBuyVip.setBuyStartTime(startTime);
        userBuyVip.setuId(userDB.getId());
        userBuyVip.setMoney(vipPrice);
        int res = userBuyVipMapper.insertSelective(userBuyVip) ;
        if(res<0){
            log.info("插入会员购买失败");
            return ResultBody.error("插入会员购买失败") ;
        }

        // 插入order表
        Order order = new Order() ;
        order.setOrderNo(orderNo);
        order.setOrderType(2);
        order.setObjId(userBuyVip.getId());
        order.setMoney(vipPrice);
        order.settPayTime(new Date());

        orderMapper.insertSelective(order) ;

        return ResultBody.success(payResultBO) ;
    }

    private Map<String, Date> getStartTimeAndEndTime(Date vipStartTime, Date vipEndTime) {
        Map<String,Date> timeMap = new HashMap() ;
        // 结束时间为空则说明开始时间结束时间均为空，则会员时间为当前时间到当天结束再加上365天
        if(vipEndTime == null){
            Date nowDate = new Date(System.currentTimeMillis()) ;
            Calendar calendar = Calendar.getInstance() ;
            calendar.setTime(nowDate);
            calendar.set(Calendar.HOUR_OF_DAY,23);
            calendar.set(Calendar.MINUTE,59);
            calendar.set(Calendar.SECOND,59);
            calendar.add(Calendar.YEAR,1);
            calendar.add(Calendar.DAY_OF_MONTH,1);
            Date endDate = calendar.getTime() ;
            timeMap.put("startTime",nowDate) ;
            timeMap.put("endTime",endDate) ;

            return timeMap ;
        }

        Calendar calendar = Calendar.getInstance() ;
        calendar.setTime(vipEndTime);
        calendar.add(Calendar.YEAR,1);
        Date endDate = calendar.getTime() ;
        timeMap.put("startTime",vipStartTime) ;
        timeMap.put("endTime",endDate) ;

        return timeMap ;

    }

    public ResultBody saveOrUpdate(UserWxInfo userWxInfo) {
        int res = -1 ;
        User user = userMapper.selectByOpenId(userWxInfo.getOpenid()) ;
        if(user ==null){
            user = new User() ;
            user.setCity(userWxInfo.getCity());
            user.setSex(userWxInfo.getSex());
            user.setCountry(userWxInfo.getCountry());
            user.setHeadimgurl(userWxInfo.getHeadimgurl());
            user.setNike(userWxInfo.getNickname());
            user.setProvince(userWxInfo.getProvince());
            user.setOpenId(userWxInfo.getOpenid());
            res = userMapper.insertSelective(user) ;
        }else{
            User user1 = new User() ;
            user1.setId(user.getId());
            user1.setCity(user.getCity());
            user1.setSex(user.getSex());
            user1.setCountry(user.getCountry());
            user1.setHeadimgurl(user.getHeadimgurl());
            user1.setNike(user.getNike());
            user1.setProvince(user.getProvince());
            user1.setOpenId(user.getOpenId());
            res = userMapper.updateByPrimaryKeySelective(user1) ;
        }
        if(res<=0){
            return ResultBody.error("更新用户信息失败") ;
        }

        // 创建session
        Date expDate = DateUtil.getBeforTime(Calendar.DAY_OF_MONTH,1) ;
        HashMap<String, Object> jwtClaims = new HashMap<String, Object>() {};
        jwtClaims.put("id", user.getId()) ;
        String token = JwtUtil.createJWT(expDate, jwtClaims);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("token", token);
        // 将token存入redis
        Long nowMill = System.currentTimeMillis() ;
        Long expMill = expDate.getTime() ;
        redisTemplate.opsForValue().set(token,token,expMill-nowMill, TimeUnit.MILLISECONDS);

        return ResultBody.success(token) ;
    }

    public User getByOpenId(String openId) {
        return userMapper.selectByOpenId(openId) ;
    }

    public int updateSelective(User user) {
        return userMapper.updateByPrimaryKeySelective(user) ;
    }

    public int save(User userDB) {
        return userMapper.insertSelective(userDB) ;
    }

    public int updateSelectiveByOpenId(User user) {
        return userMapper.updateSelectiveByOpenId(user);
    }

    public ResultBody<UserVO> register(UserRegisterAO userRegisterAO) {
        UserVO userVO = new UserVO() ;
        if(!redisTemplate.hasKey(GlobalValue.userCodeRedisKey(userRegisterAO.getPhone()))){
            throw new BizException(CommonEnum.LOGIN_SMS_ERROR) ;
        }
        String cacheCode = (String) redisTemplate.opsForValue().get(GlobalValue.userCodeRedisKey(userRegisterAO.getPhone()));
        log.info("缓存中验证码cacheCode：：{}",cacheCode);
        if(!userRegisterAO.getSmsCode().equals(cacheCode)){
            throw new BizException(CommonEnum.LOGIN_SMS_ERROR) ;
        }
        User userDB = getByOpenId(userRegisterAO.getOpenId()) ;
        if(userDB != null){
            log.info("该用户已经为会员，进入登录流程");
            if(!userDB.getPhone().equals(userRegisterAO.getPhone())){
                return ResultBody.error(CommonEnum.LOGIN_PHONE_NOT_MATCH_ERROR) ;
            }
            String token = login(userDB) ;
            BeanUtils.copyProperties(userDB,userVO);
            userVO.setToken(token);
            return ResultBody.success(userVO) ;
        }
        log.info("进入注册流程");

        User user = new User() ;
        if(StringUtils.isBlank(userRegisterAO.getNickname())){
            user.setNike(userRegisterAO.getNickname());
        }
        if(StringUtils.isBlank(userRegisterAO.getHeadimgurl())){
            user.setHeadimgurl(userRegisterAO.getHeadimgurl());
        }
        user.setPhone(userRegisterAO.getPhone());
        user.setOpenId(userRegisterAO.getOpenId());


        Integer res = userMapper.insertSelective(user);
        if(res<=0){
            return ResultBody.error(CommonEnum.REGISTER_ERROR) ;
        }
        log.info("res:::{}",res);
        log.info("user:::::::::{}",user);
        String token = login(user) ;

        BeanUtils.copyProperties(user,userVO);
        userVO.setToken(token);

        return ResultBody.success(userVO) ;
    }

    public String login(User userDB) {

        Date expDate = DateUtil.getBeforTime(Calendar.DAY_OF_MONTH,1) ;
        HashMap<String, Object> jwtClaims = new HashMap<String, Object>() {};
        jwtClaims.put("id", userDB.getId()) ;
        String token = JwtUtil.createJWT(expDate, jwtClaims);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("token", token);
        // 将token存入redis
        Long nowMill = System.currentTimeMillis() ;
        Long expMill = expDate.getTime() ;
        redisTemplate.opsForValue().set(token,token,expMill-nowMill, TimeUnit.MILLISECONDS);

        return token ;
    }

    public ResultBody<User> detail(Long id) {
        User user = getById(id) ;
        if(user == null){
            throw new BizException("查询用户失败")  ;
        }
        return ResultBody.success(user) ;
    }

    public JSONObject buyVipNotify(HttpServletRequest request) {
        JSONObject jsonObject = new JSONObject() ;
        PayNotifyRequest payNotifyRequest = payService.getNotifyData(request) ;
        log.info("payNotifyRequest::::::{}",payNotifyRequest);
        if(TradeState.SUCCESS.getCode().equals(payNotifyRequest.getTrade_state())){
            log.info("用户支付成功");
            // 如果是其他逻辑
            //  更新新t_user表，vip vip_start_time vip_end_time
            //先计算出本次购买的会员的开始时间和结束时间，如果用户现在已经有会员，则开始时间为用户会员结束时间累加365天，如果用户没有会员则会员天数为当前时间到24点再加上365天
            String orderNo = payNotifyRequest.getOut_trade_no() ;
            Order order = orderMapper.selectByOrderNO(orderNo) ;
            if(order == null){
                log.info("查无此订单");
                jsonObject.put("code","FAIL") ;
                jsonObject.put("message","查无此订单") ;
                return  jsonObject ;
            }
            User userDB = userMapper.selectByPrimaryKey(order.getObjId()) ;
            userDB.setVip(VipEnum.VIP.getCode());

            Map<String , Date> timeMap = getStartTimeAndEndTime(userDB.getVipStartTime(),userDB.getVipEndTime()) ;
            Date startTime = timeMap.get("startTime") ;
            Date endTime = timeMap.get("endTime") ;
            userDB.setVipStartTime(startTime);
            userDB.setVipEndTime(endTime);
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") ;
            log.info("结束时间：：：{}",simpleDateFormat.format(endTime));
            userMapper.updateByPrimaryKeySelective(userDB) ;

            Long buyVipId = order.getObjId() ;
            UserBuyVip  userBuyVip = userBuyVipMapper.selectByPrimaryKey(buyVipId) ;

            // 新增用户VIP购买记录表t_user_buy_vip
            userBuyVip.setStatus(TradeStatusEnum.PAY_SUCCESS.getCode());
            userBuyVip.setuId(userDB.getId());
            userBuyVip.setMoney(vipPrice);
            int res = userBuyVipMapper.updateByPrimaryKeySelective(userBuyVip) ;
            if(res<0){
                jsonObject.put("code","FAIL") ;
                jsonObject.put("message","查无此订单") ;
                return jsonObject ;
            }

            // 发送会员购买成功推送消息
            Date d = new Date() ;
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") ;
            String dateStr = format.format(d) ;
            JSONObject keyword1 = new JSONObject() ;
            keyword1.put("value",vipPrice+"元") ;
            keyword1.put("color","#FF0000") ;
            jsonObject.put("keyword1",keyword1) ;
            JSONObject keyword2 = new JSONObject() ;
            keyword2.put("value",userDB.getNike()) ;
            jsonObject.put("keyword2",keyword2) ;
            //keyword2.put("color","#FF0000") ;
            JSONObject keyword3 = new JSONObject() ;
            keyword3.put("value",dateStr) ;
            keyword3.put("color","#FF0000") ;
            jsonObject.put("keyword3",keyword3) ;
            JSONObject keyword4 = new JSONObject() ;
            String endTimeStr = format.format(endTime) ;
            keyword4.put("value",endTimeStr) ;
            jsonObject.put("keyword4",keyword4) ;
            keyword4.put("color","#FF0000") ;
            JSONObject first = new JSONObject() ;
            first.put("value",title) ;
            jsonObject.put("first",title) ;
            JSONObject remarkk = new JSONObject() ;
            remarkk.put("value",remark) ;
            jsonObject.put("remark",remarkk) ;

            pushMessageService.send(jsonObject,templateId,userDB.getOpenId(),"http://www.baidu.com") ;

            return null ;
        }
        log.info("支付失败");

        jsonObject.put("code","FAIL") ;
        jsonObject.put("message","支付失败") ;
        return jsonObject ;


    }

    /**
     * @author jiangguanjun
     * @date 2023/11/1 10:11
     * @param
     * @return
     * @desc 退款回调
     */
    public JSONObject refundNotify(HttpServletRequest request) {
        JSONObject jsonObject = new JSONObject() ;
        RefundNotifyRequest refundNotifyData = payService.getRefundNotifyData(request) ;
        log.info("refundNotifyData::::::{}",refundNotifyData);
        String refundId = refundNotifyData.getRefund_id() ;
        Refund refund = refundMapper.selectByRefundId(refundId) ;
        if(refund == null){
            log.warn("未查到退款订单");
            jsonObject.put("code","SUCCESS") ;
            return jsonObject ;
        }
        if(RefundState.SUCCESS.getCode().equals(refund)){
            log.info("状态为成功状态，无需操作");
            jsonObject.put("code","SUCCESS") ;
            return jsonObject ;
        }
        if(RefundState.SUCCESS.getCode().equals(refundNotifyData.getRefund_status())){
            log.info("退款成功");
            //  更新新t_user表，vip vip_start_time vip_end_time
            //先计算出本次购买的会员的开始时间和结束时间，如果用户现在已经有会员，则开始时间为用户会员结束时间累加365天，如果用户没有会员则会员天数为当前时间到24点再加上365天
            Integer orderId = refund.getOrderId() ;
            Order order = orderMapper.selectByPrimaryKey(orderId) ;
            User userDB = userMapper.selectByPrimaryKey(order.getObjId()) ;
            Date startTimeDB = userDB.getVipStartTime() ;
            Date endTimeDB = userDB.getVipEndTime() ;
            Calendar startCal = Calendar.getInstance();
            startCal.setTime(startTimeDB);
            Calendar endCal = Calendar.getInstance();
            endCal.setTime(endTimeDB);
            startCal.add(Calendar.YEAR,-1);
            endCal.add(Calendar.YEAR,-1);
            Integer vip = VipEnum.VIP.getCode() ;
            if(endCal.compareTo(Calendar.getInstance())<0){
                log.info("退款之后结束时间小于当前时间需要取消该用户的vip");
                vip = VipEnum.VIP.getCode() ;
            }

            userDB.setVipStartTime(startCal.getTime());
            userDB.setVipEndTime(endCal.getTime());
            userDB.setVip(vip);

            userMapper.updateByPrimaryKeySelective(userDB) ;

            // 新增用户VIP购买记录表t_user_buy_vip
            UserBuyVip userBuyVip = new UserBuyVip() ;
            userBuyVip.setBuyEndTime(endCal.getTime());
            userBuyVip.setBuyStartTime(startCal.getTime());
            userBuyVip.setuId(userDB.getId());
            userBuyVip.setMoney(-vipPrice);
            userBuyVip.setStatus(TradeStatusEnum.REFUND_SUCCESS.getCode());
            int res = userBuyVipMapper.insertSelective(userBuyVip) ;
            if(res<0){
                jsonObject.put("code","FAIL") ;
                jsonObject.put("message","更新失败") ;
                return jsonObject ;
            }

            jsonObject.put("code","SUCCESS") ;
            jsonObject.put("message","退款成功") ;
            return jsonObject ;

        }

        jsonObject.put("code","FAIL") ;
        jsonObject.put("message","支付失败") ;
        return jsonObject ;
    }

    public ResultBody<IPage<AccountDetailVO>> myAccount(AccountBO accountBO) {
        MyPage myPage = PageConfig.getPage() ;
        Page<AccountDetailVO> page = new Page<>(myPage.getPageNum(),myPage.getPageSize()) ;
        IPage<AccountDetailVO> iPage = accountDetailMapper.queryPage(page,accountBO) ;
        List<AccountDetailVO> accountDetailVOS = iPage.getRecords() ;
        accountDetailVOS.forEach(accountDetailVO -> {
            accountDetailVO.setBusiTypeStr(AccountBusiTypeEnum.getDescByCode(accountDetailVO.getBusiType()));
        });
        return ResultBody.success(iPage) ;
    }


    /*public ResultBody<RefundResult> refund(RefundAO refundAO) {
        Integer id = refundAO.getId() ;

        UserBuyVip userBuyVip = userBuyVipMapper.selectByPrimaryKey(id) ;
        Order order = orderMapper.selectByObjId(userBuyVip.getId()) ;
        RefundBO refundBO = new RefundBO() ;
        refundBO.setOrderId(order.getId());
        String outRefundNo = "rechargeRefund"+IdUtils.getId() ;
        log.info("outRefundNo::::::::::::::{}",outRefundNo);
        refundBO.setOut_refund_no(outRefundNo);
        RefundBO.RefundAmount refundAmount = new RefundBO.RefundAmount() ;
        refundAmount.setRefund(refundAO.getMoney());
        refundBO.setRefundAmount(refundAmount);
        refundBO.setuId(order.getuId());
        refundBO.setReason(refundAO.getReason());
        refundBO.setOut_trade_no(order.getOrderNo());
        refundBO.setNotify_url(notifyBase+buyVipRefundNotify);
        RefundResult refundResult = payService.refundByOut(refundBO) ;
        if(refundResult == null){
            return ResultBody.error("退款失败") ;
        }


        return ResultBody.success(refundResult) ;
    }*/
}
